﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ServerClientCommon;

namespace SensorClient
{
    public enum SensorConsumerType
    {
        EMULATOR = 0,
        CROSSBOW = 1,
        FEZPANDA = 2,
    }

    public class SensorMaster
    {

        #region Constants
        /// <summary>
        /// The default period used for sensor data acquistions
        /// </summary>
        private const int DEFAULT_PERIOD = 10000;
        /// <summary>
        /// The default path to the xml file
        /// </summary>
        private const string DEFAULT_XML_PATH = "data.xml";
        /// <summary>
        /// The default ip used
        /// </summary>
        private string DEFAULT_IP = "127.0.0.1";
        /// <summary>
        /// The default used port
        /// </summary>
        private int DEFAULT_PORT = 3000;
        /// <summary>
        /// The default module id
        /// </summary>
        private int DEFAULT_MODULE_ID = 50;
        #endregion

        #region Members
        /// <summary>
        /// The object used for reading/emulating sensor values
        /// </summary>
        private SensorConsumer _sensorConsumer;
        /// <summary>
        /// The id of the module
        /// </summary>
        private int _moduleId;
        /// <summary>
        /// The preset used for non-boolean sensors
        /// </summary>
        private NormalSensorsPreset _normalSensorsPreset;
        /// <summary>
        /// The preset used for boolean sensors
        /// </summary>
        private BooleanSensorsPreset _booleanSensorsPreset;
        /// <summary>
        /// The object used for converting from raw values to real values (for sensors)
        /// </summary>
        private SensorContainerAdapter _sensorAdapter;
        /// <summary>
        /// The object used for estabilishing a TCP connection
        /// </summary>
        private TcpClientModel _clientModel;
        /// <summary>
        /// Used for signaling the first transmission
        /// </summary>
        private bool _hasSentId;
        /// <summary>
        /// Contains the ip
        /// </summary>
        private string _ipString;
        /// <summary>
        /// The port 
        /// </summary>
        private int _port;
        /// <summary>
        /// The serial port 
        /// </summary>
        private string _serialPort;
        #endregion

        #region Constructors
        /// <summary>
        /// The constructor used for creating a SensorMaster object
        /// </summary>
        /// <param name="moduleId">The id of the module</param>
        /// <param name="useEmulator">if true it will use the emulator, otherwise it will 
        /// use the crossbow module</param>
        /// <param name="normalSensorsPresets">the preset for non-boolean sensors</param>
        /// <param name="booleanSensorsPresets">the preset used for boolean sensors</param>
        public SensorMaster(int moduleId, SensorConsumerType consumerType,
                            NormalSensorsPreset normalSensorsPresets,
                            BooleanSensorsPreset booleanSensorsPresets,
                            string ipString, int port)
        {
            switch(consumerType)
            {
                case SensorConsumerType.CROSSBOW:
                     _sensorConsumer = new SensorCrossbow(DEFAULT_PERIOD);
                    break;
                case SensorConsumerType.FEZPANDA:
                    _sensorConsumer = new SensorPanda(DEFAULT_PERIOD, null);
                    break;
                default:
                    _sensorConsumer = new SensorEmulator(DEFAULT_PERIOD);
                    break;

            }
            _moduleId = moduleId;
            _sensorConsumer.StartConsumer();
            _normalSensorsPreset = normalSensorsPresets;    //Shallow copy
            _booleanSensorsPreset = booleanSensorsPresets;  //Shallow copy
            _sensorAdapter = new SensorContainerAdapter(_normalSensorsPreset,
                                                        _booleanSensorsPreset,
                                                        _moduleId);
            _ipString = ipString;
            _port = port;
            _clientModel = new TcpClientModel(_ipString, _port);
            _clientModel.Connect();
            _hasSentId = false;

        }
        /// <summary>
        /// The constructor used for creating a SensorMaster object
        /// </summary>
        /// <param name="moduleId">The id of the module</param>
        /// <param name="useEmulator">if true it will use the emulator, otherwise it will 
        /// use the crossbow module</param>
        /// <param name="normalSensorsPresets">the preset for non-boolean sensors</param>
        /// <param name="booleanSensorsPresets">the preset used for boolean sensors</param>
        /// <param name="ipString">A string containing the ip</param>
        /// <param name="port">The port used for TCP/IP connection</param>
        /// <param name="comPort">The serial port used for data acquisition</param>
        public SensorMaster(int moduleId, SensorConsumerType consumerType,
                            NormalSensorsPreset normalSensorsPresets,
                            BooleanSensorsPreset booleanSensorsPresets,
                            string ipString, int port, string comPort)
        {
                switch (consumerType)
                {
                    case SensorConsumerType.CROSSBOW:
                        _sensorConsumer = new SensorCrossbow(DEFAULT_PERIOD);
                        break;
                    case SensorConsumerType.FEZPANDA:
                        _sensorConsumer = new SensorPanda(DEFAULT_PERIOD, comPort);
                        break;
                    default:
                        _sensorConsumer = new SensorEmulator(DEFAULT_PERIOD);
                        break;

                }
                _moduleId = moduleId;
                _serialPort = comPort;
                _sensorConsumer.StartConsumer();
                _normalSensorsPreset = normalSensorsPresets;    //Shallow copy
                _booleanSensorsPreset = booleanSensorsPresets;  //Shallow copy
                _sensorAdapter = new SensorContainerAdapter(_normalSensorsPreset,
                                                            _booleanSensorsPreset,
                                                            _moduleId);
                _ipString = ipString;
                _port = port;
                _clientModel = new TcpClientModel(_ipString, _port);
                _clientModel.Connect();
                _hasSentId = false;
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Used for reading a file into a string
        /// </summary>
        /// <param name="path">the path to the file</param>
        /// <returns>a string containing all data in the file</returns>
        private string ReadString(string path)
        {
            StreamReader reader = new StreamReader(path);
            string text = reader.ReadToEnd();
            reader.Close();
            return text;
        }
        #endregion

        #region Public methods
        /// <summary>
        /// The method used for enabling the SensorMaster
        /// </summary>
        public void Start()
        {
            _sensorConsumer.SensorsReceived +=
                new SensorEmulator.SensorsReceivedHandler(senCons_SensorsReceived);
        }
        /// <summary>
        /// The method used for disabling the SensorMaster
        /// </summary>
        public void Stop()
        {
            _sensorConsumer.SensorsReceived -=
                new SensorEmulator.SensorsReceivedHandler(senCons_SensorsReceived);
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Event that fires everyime a sensor acquistion is over
        /// </summary>
        /// <param name="sender">The object who sents the event</param>
        /// <param name="e">Arguments containing the information about the sensor values</param>
        protected void senCons_SensorsReceived(object sender, SensorsReceivedArgs e)
        {
            SensorContainer sc = _sensorAdapter.ConvertRawToReal(e.Package);
            Console.WriteLine(sc.ToString() + "\n\n\n");
            if (_hasSentId == false)
            {
                _clientModel.SendMessage(_moduleId.ToString());
                _hasSentId = true;
            }
            _clientModel.SendMessage(sc.GetXmlString());
        }
        #endregion
    }
}


